/*-+-*****************************************************************************
 Copyright (C) 2009-2012 Oceanside Software Corporation (R)
 Dallas, Texas

 Author       : Jason T. Brower
 Purpose      : This file is part of a point-of-sale software package
                originally written for Table-Service Restaurants.
              
 Date         : July 8th of 2012
              
 History      : The application that this software file belongs to was 
                written over a 3-Year period.  The first version was written
                in C# .Net 3.5 using Windows Forms.  Being new to .Net at
                the time, I soon learned of Windows Presentation Foundation,
                liked the graphics capabilities and databinding so I
                migrated to WPF.  When the .Net 4.0 framework was released
                the application was migrated from 3.5 to 4.0. Now today,
                .Net 4.5 RC is out and I was already in process of migrating
                before I made this public.
                
Excuse Me     : Please excuse the coding style, it is not representative of
                my typical work.  During the three years I was under a very
                tight budget, constantly running out of funding and was 
                working 18 hour days hyped up on 5-Hour Energy.  The 
                design is not textbook.  It is monolythic because of
                previous issues I will not get into.  There are few comments
                in the code and the ones that are there may be incorrect.
                
What it is not: This is not the exact version that I took through PA-DSS 2.0
                nor is it the exact version running at my customer sites.
                I removed some details for security purposes including some
                encryption algorithms.  The reporting was removed because
                I was including a third party library that cannot be 
                published with this Open Source.
                
What it is    : This application has been running at high volume restaraunts
                for over a year.  It never freezes, crashes or does anything
                unexpected.  So long as it is built, installed and configured
                correctly, it is a strong system that we can all enhance.

Contact       : Please note that I can no longer work for free.  However, you
                can reach me at information@oceansidesw.com.                                                      

*********************************************************************************/
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace Oceanside
{
    /// <summary>
    /// Interaction logic for KeyboardKey.xaml
    /// </summary>
    public partial class KeyboardKey : UserControl
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        public KeyboardKey()
        {
            this.InitializeComponent();
            this.MouseDown += new MouseButtonEventHandler(KeyboardKey_MouseDown_NOTHROW);
            this.MouseLeave += new MouseEventHandler(Key_MouseLeave_NOTHROW);
            this.MouseUp += new MouseButtonEventHandler(Key_MouseUp_NOTHROW);
        }

        /// <summary>
        /// Used for GUI keyboard input.
        /// </summary>
        private const int CONST_SPACES_IN_TAB = 5;

        /// <summary>
        /// This will only be true for one or two keys.  We need this flag so we can lock the caps key
        /// in its alternative pressed color and unlock it back to normal when it is pressed again.
        /// </summary>
        private bool isCapLockKey = false;
        public bool IsCapLockKey
        {
            get { return isCapLockKey; }
            set { isCapLockKey = value; }
        }
        private static bool capsIsLocked = false;

        public static bool CapsIsLocked
        {
            get { return KeyboardKey.capsIsLocked; }
            set { KeyboardKey.capsIsLocked = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public void ResetBorder()
        {
            borderKey.Background = ButtonBackground;
        }

        /// <summary>
        /// 
        /// </summary>
        public void HighlightBorder()
        {
            borderKey.Background = ButtonBackgroundMouseDown;
        }

        /// <summary>
        /// One time static constructor for the dependency properties.
        /// </summary>
        static KeyboardKey()
        {
            ///Note the lack of metadata thats not needed for the background mouse down prop.
            ButtonBackgroundMouseDownProperty = DependencyProperty.Register("ButtonBackgroundMouseDown", typeof(Brush), typeof(KeyboardKey));

            ///Regular Background
            FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata(new PropertyChangedCallback(OnButtonBgChanged));
            ButtonBackgroundProperty = DependencyProperty.Register(
                "ButtonBackground",
                typeof(Brush),
                typeof(KeyboardKey),
                metadata);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public static void OnButtonBgChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            KeyboardKey key = sender as KeyboardKey;

            if (key != null && key.borderKey != null)
            {
                key.borderKey.Background = (Brush)args.NewValue;
            }
        }

        /// <summary>
        /// Background color of the key when it is pressed.
        /// </summary>
        public static readonly DependencyProperty ButtonBackgroundMouseDownProperty;
        public Brush ButtonBackgroundMouseDown
        {
            get { return (Brush)GetValue(ButtonBackgroundMouseDownProperty); }
            set { SetValue(ButtonBackgroundMouseDownProperty, value); }
        }

        /// <summary>
        /// Background color of the key.
        /// </summary>
        public static readonly DependencyProperty ButtonBackgroundProperty;
        public Brush ButtonBackground
        {
            get
            {
                return (Brush)GetValue(ButtonBackgroundProperty);
            }
            set { SetValue(ButtonBackgroundProperty, value); }
        }

        /// <summary>
        /// Click Events
        /// </summary>
        void Key_MouseUp_NOTHROW(object sender, MouseButtonEventArgs e)
        {
            try
            {
                e.Handled = true;
                if (!isCapLockKey || !capsIsLocked)
                {
                    borderKey.Background = ButtonBackground;
                }
                else
                {
                    borderKey.Background = ButtonBackgroundMouseDown;
                }
            }
            catch (System.Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_BUTTON_KEYBOARD_KEY_MOUSEUP, exc);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param Name="sender"></param>
        /// <param Name="e"></param>
        void Key_MouseLeave_NOTHROW(object sender, MouseEventArgs e)
        {
            try
            {
                e.Handled = true;
                if (!isCapLockKey || !capsIsLocked)
                {
                    borderKey.Background = ButtonBackground;
                }
                else
                {
                    borderKey.Background = ButtonBackgroundMouseDown;
                }
            }
            catch (System.Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_BUTTON_KEYBOARD_KEY_MOUSELEAVE, exc);
            }
        }

        /// <summary>
        /// Event handler for when the user presses the keyboard key.
        /// </summary>
        /// <param Name="sender"></param>
        /// <param Name="e"></param>
        void KeyboardKey_MouseDown_NOTHROW(object sender, MouseButtonEventArgs e)
        {
            try
            {
                e.Handled = true;
                if (isCapLockKey)
                {
                    capsIsLocked = !capsIsLocked;
                }
                borderKey.Background = ButtonBackgroundMouseDown;
                KeyboardKey key = sender as KeyboardKey;

                UInt32 val = Convert.ToUInt32(key.Tag);
                ProcessScanCode((System.Windows.Forms.Keys)val);
            }
            catch (System.Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_BUTTON_KEYBOARD_KEY_MOUSEDWN, exc);
            }
        }

        /// <summary>
        /// When the GUI keyboard has popped open for the user to enter magnetic card data instead of using the MSR,
        /// then each key will hit this callback so we can determine how to process and display the data on the
        /// GUI.
        /// </summary>
        /// <param name="scanCode"></param>
        private static void ProcessScanCode(System.Windows.Forms.Keys scanCode)
        {
            try
            {
                ///Check for backspace first because of the prevCharWasTab flag.
                if (scanCode == System.Windows.Forms.Keys.Back)  //Backspace
                {
                    lock (FullKeyboard.GuiKeyPressStringLocker)
                    {
                        if (FullKeyboard.GuiKeyPressedString.Length != 0)
                        {
                            FullKeyboard.GuiKeyPressedString =
                                FullKeyboard.GuiKeyPressedString.Substring(0, FullKeyboard.GuiKeyPressedString.Length - 1);

                            FullKeyboard.ActiveKeyboard.TextBoxValue = FullKeyboard.GuiKeyPressedString;
                        }
                    }
                }
                else ///Not a backspace
                {
                    ///Should we clear the string?
                    if (scanCode == System.Windows.Forms.Keys.Clear)
                    {
                        ClearTextString();
                    }
                    ///Did the user request to close the keyboard?
                    else if (scanCode == System.Windows.Forms.Keys.Cancel)
                    {
                        ClearTextString();
                        FullKeyboard.ActiveKeyboard.HideMe(isCancel: true);
                    }
                    ///Are they submitting their data?
                    else if (scanCode == System.Windows.Forms.Keys.Enter)
                    {
                        FullKeyboard.ActiveKeyboard.HideMe(isCancel: false);
                    }
                    ///Inject spaces? Don't allow leading spaces because if it is a credit card 
                    ///number or card date, it will be an issue.
                    else if (scanCode == System.Windows.Forms.Keys.Tab)
                    {
                        FullKeyboard.TabDetected();
                    }
                    ///Must be an actual character key?
                    else
                    {
                        ///Translate the scancode to asii.
                        String tmpString = FullKeyboard.CodeScanFormatter.ScancodeToAsciiStrChar(scanCode);

                        if (tmpString != null)
                        {
                            ///Prevent leading spaces.
                            if (!(FullKeyboard.GuiKeyPressedString.Equals("") && tmpString.Equals(" ")))
                            {
                                lock (FullKeyboard.GuiKeyPressStringLocker)
                                {
                                    if (FullKeyboard.UseAutoCapsMode)
                                    {
                                        int lastIndex = FullKeyboard.GuiKeyPressedString.Length - 1;
                                        if (FullKeyboard.GuiKeyPressedString.Equals("") ||
                                            (lastIndex >= 0 && FullKeyboard.GuiKeyPressedString[lastIndex] == ' '))
                                        {
                                            tmpString = tmpString.ToUpper();
                                        }
                                    }
                                    FullKeyboard.GuiKeyPressedString += tmpString;
                                    FullKeyboard.ActiveKeyboard.TextBoxValue = FullKeyboard.GuiKeyPressedString;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logging.LogException(e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private static void ClearTextString()
        {
            if (FullKeyboard.ActiveKeyboard != null)
            {
                FullKeyboard.ActiveKeyboard.TextBoxValue = "";
            }
            FullKeyboard.GuiKeyPressedString = "";
        }

        /// <summary>
        /// This is the Name of the key or face of the key when in normal not
        /// alt mode.
        /// </summary>
        public string KbKeyname
        {
            get { return Keyname.Text; }
            set
            {
                Keyname.Text = value;
            }
        }

        /// <summary>
        /// This is the Name of the key or face of the key when in shift mode.
        /// </summary>
        public string KbKeyAltname
        {
            get { return AltName.Text; }
            set
            {
                AltName.Text = value;
            }
        }

        /// <summary>
        /// This is how far off the bottom of the button the text will lay.
        /// </summary>
        public double TextBottomMargin
        {
            get { return Keyname.Margin.Bottom; }
            set { Keyname.Margin = new Thickness(0, 0, 0, value); }
        }

        /// <summary>
        /// Size of the font used for the buton.
        /// </summary>
        public double TextFontSize
        {
            get { return Keyname.FontSize; }
            set
            {
                Keyname.FontSize = value;
                AltName.FontSize = value;
            }
        }

        /// <summary>
        /// Vertical alignment of the text on the button.
        /// </summary>
        public VerticalAlignment TextVAlign
        {
            get { return Keyname.VerticalAlignment; }
            set { Keyname.VerticalAlignment = value; }
        }

        /// <summary>
        /// Horizontal alignment of the text on the button.
        /// </summary>
        public HorizontalAlignment TextHAlign
        {
            get { return Keyname.HorizontalAlignment; }
            set { Keyname.HorizontalAlignment = value; }
        }
    }
}
